﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

using Newtonsoft.Json.Linq;
using Jim.Obsidian.Edm;
using Jim.Obsidian.Utilities;

namespace Jim.Obsidian.Web.Api
{
    public class ApiRequest
    {

        private JObject joData;
        private string _action;
        private string _message;
        private List<ApiSubResult> _subResults = new List<ApiSubResult>();
        private string _typeName;
        private string _methodName;

        public string Action
        {
            get { return this._action; }
        }

        public string Message
        {
            get { return this._message; }
            set { this._message = value; }
        }

        public string TypeName
        {
            get { return this._typeName; }
        }

        public string MethodName
        {
            get { return this._methodName; }
        }

        public List<ApiSubResult> SubResults
        {
            get { return this._subResults; }
        }

        public ApiSubResult AddSubResult(string name, string jprops)
        {
            ApiSubResult subrs = new ApiSubResult(name, jprops);
            this._subResults.Add(subrs);
            return subrs;
        }

        public ApiRequest(JObject jo)
        {
            JValue jv = (JValue)jo["act"];
            this._action = Convert.ToString(jv.Value);
            joData = (JObject)jo["data"];
            
            if (this._action.IndexOf(".") <= 0)
            {
                this._message = "参数act错误!";
                return;
            }
            string apiNamespace = AppConfig.GetApiNamespace();
            if (String.IsNullOrEmpty(apiNamespace))
                throw new Exception("未配置apiNamespace参数");

            string fullPath = apiNamespace + "." + this._action;
            string[] ns = fullPath.Split('.');

            StringBuilder sb = new StringBuilder();
            int i = 0;
            for (; i < ns.Length - 1; i++)
            {
                sb.Append(StringUtility.FirstUpper(ns[i]) + ".");
            }
            sb.Remove(sb.Length - 1, 1);

            this._typeName = sb.ToString();
            this._methodName = StringUtility.FirstUpper(ns[i]);

        }

        public bool ExistsParam(string name)
        {
            JToken jt = joData[name];
            return jt != null;
        }

        public string GetResultsJsonString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("{\"d\":[");
            if (this._subResults.Count > 0)
            {
                foreach (ApiSubResult rs in this._subResults)
                {
                    sb.Append(rs.ToJsonString());
                    sb.Append(",");
                }
                sb.Remove(sb.Length - 1, 1);
            }
            sb.Append("]}");
            return sb.ToString();
        }

        public object GetValue(string name)
        {
            if (joData == null)
                return null;
            JToken jt = joData[name];
            if (jt == null)
                return null;
            JValue jv = (JValue)jt;
            return jv.Value;
        }

        public string GetString(string name)
        {
            object val = this.GetValue(name);
            if (val == null)
                return null;
            else
                return Convert.ToString(val);
        }

        public Dictionary<string, string> GetDict()
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            IEnumerable<JProperty> jProps = joData.Properties();
            foreach (JProperty jProp in jProps)
            {
                string propName = jProp.Name;
                string val = Convert.ToString(((JValue)jProp.Value).Value);
                dict.Add(propName, val);
            }
            return dict;
        }

        public T GetModel<T>() where T : Model, new()
        {
            T m = new T();
            foreach (IModelField f in m.Fields)
            {
                string propName = f.JPropName;
                if (!String.IsNullOrEmpty(propName))
                {
                    JToken jt = joData[propName];
                    if (jt != null)
                    {
                        try
                        {
                            JValue jv = (JValue)jt;
                            f.Set(jv.Value);
                        }
                        catch { }
                    }
                }
            }
            return m;
        }

        public bool TryGetString(string name, out string result)
        {
            object o = this.GetValue(name);
            if (o == null)
            {
                result = null;
                return false;
            }
            result = Convert.ToString(o);
            return true;
        }

        public bool GetBool(string name)
        {
            object val = this.GetValue(name);
            return Convert.ToBoolean(val);
        }

        public bool TryGetBool(string name, out bool result)
        {
            string str = this.GetString(name);
            return bool.TryParse(str, out result);
        }

        public int GetInt(string name)
        {
            object val = this.GetValue(name);
            return Convert.ToInt32(val);
        }

        public bool TryGetInt(string name, out int result)
        {
            string str = this.GetString(name);
            return int.TryParse(str, out result);
        }

        public bool TryGetFloat(string name, out float result)
        {
            object o = this.GetValue(name);
            if (o == null)
            {
                result = -1;
                return false;
            }
            result = Convert.ToSingle(o);
            return true;
        }

        public long GetLong(string name)
        {
            object val = this.GetValue(name);
            return Convert.ToInt64(val);
        }

        public bool TryGetLong(string name, out long result)
        {
            string str = this.GetString(name);
            return long.TryParse(str, out result);
        }

        public DateTime GetDateTime(string name)
        {
            object val = this.GetValue(name);
            return Convert.ToDateTime(val);
        }

        public bool TryGetDateTime(string name, out DateTime result)
        {
            string str = this.GetString(name);
            return DateTime.TryParse(str, out result);
        }

        public decimal GetDecimal(string name)
        {
            object val = this.GetValue(name);
            return Convert.ToDecimal(val);
        }

        public bool TryGetDecimal(string name, out decimal result)
        {
            string str = this.GetString(name);
            return decimal.TryParse(str, out result);
        }

        public double GetDouble(string name)
        {
            object val = this.GetValue(name);
            return Convert.ToDouble(val);
        }

        public bool TryGetDouble(string name, out double result)
        {
            string str = this.GetString(name);
            return double.TryParse(str, out result);
        }

    }
}
